package com.wfh.easychat.websocket;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Title: WebSocketHandler
 * @Author wangfenghuan
 * @Package com.wfh.easychat.websocket
 * @Date 2025/10/5 13:49
 * @description: ws处理器
 */
@Slf4j
public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    /**
     * 保存已经建立好连接点对点的channel
     */
    private final Map<Object, Channel> channelMap = new ConcurrentHashMap<>();

    /**
     * 群聊消息channelmap
     */
    private final Map<Object, ChannelGroup> channelGroupMap = new ConcurrentHashMap<>();


    /**
     * 进行校验
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete complete){
            String s = complete.requestUri();
            log.info("请求地址：{}", s);
            String token = getToken(s);
            // 如果token为空的话直接关闭当前的连接
            if (token == null){
                ctx.channel().close();
            }
            // 将当前校验通过的channel放到map中去
            String channelId = ctx.channel().id().asLongText();
            channelMap.put(channelId, ctx.channel());
            AttributeKey attributeKey = null;
            if (!AttributeKey.exists(channelId)){
                attributeKey = AttributeKey.newInstance(channelId);
            }else {
                attributeKey = AttributeKey.valueOf(channelId);
            }
            ctx.channel().attr(attributeKey).set(token);
            addGroup("100", ctx.channel());
            sendGroup("你好");
        }
    }

    /**
     * 频道就绪后，调用
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("有新的连接加入");
    }

    /**
     * 读取消息
     * @param channelHandlerContext
     * @param textWebSocketFrame
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
        Channel channel = channelHandlerContext.channel();
        Attribute<String> attribute = channel.attr(AttributeKey.valueOf(channel.id().asLongText()));
        String userId = attribute.get();
        log.info("收到消息用户{}的消息:{}",userId,  textWebSocketFrame.text());
    }

    /**
     * 连接断开
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("{}连接断开", ctx.channel().id());
    }

    private String getToken(String uri){
        if (StringUtils.isEmpty(uri) || !uri.contains("?")){
            return null;
        }
        String[] split = uri.split("\\?");
        if (split.length != 2){
            return null;
        }
        return split[1];
    }

    /**
     * 添加到群聊消息
     * @param groupId
     * @param channel
     */
    private void addGroup(String groupId, Channel channel){
        ChannelGroup channels = channelGroupMap.get(groupId);
        if (channels == null){
            channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
            channelGroupMap.put(groupId, channels);
        }
        if (channel == null){
            return;
        }
        channels.add(channel);
    }

    /**
     * 向这个组中发送消息
     * @param message
     */
    private void sendGroup(String message){
        ChannelGroup channels = channelGroupMap.get("100");
        channels.writeAndFlush(new TextWebSocketFrame(message));
    }
}
